home *** CD-ROM | disk | FTP | other *** search
- /* ================================================================== *
- * Editor mined *
- * auxiliary part *
- * ================================================================== */
-
- #include "mined.h"
-
- int panic_level = 0; /* To adjust error handling to situation */
- FLAG pagewrapped = FALSE; /* Did output on the bottom line wrap and scroll? */
-
- /* ================================================================== *
- * Auxiliary routines *
- * ================================================================== */
-
- /*
- * Delete file.
- */
- void
- delete_file (file)
- char * file;
- {
- #ifdef unix
- unlink (file);
- #endif
- #ifdef msdos
- unlink (file);
- #endif
- #ifdef vms
- delete (file);
- #endif
- }
-
- /*
- * Delete yank file if there is one.
- */
- void
- delete_yank_file ()
- {
- if (yank_status == VALID) delete_file (yank_file);
- }
-
- /*
- * Panic () is called with a mined error msg and an optional system error msg.
- * It is called when something unrecoverable has happened.
- * It writes the message to the terminal, resets the tty and exits.
- * Ask the user if he wants to save his file.
- */
- #define panic_msg(msg) if (isscreenmode == TRUE) {status_msg (msg); sleep (2);} else (void) printf ("%s\n", msg);
- void
- panicking (message, err, signum)
- register char * message;
- register char * err;
- register int signum;
- {
- int panic_written;
- void QUED ();
-
- panic_level ++;
-
- if (panic_level < 2) {
- if (loading == FALSE && modified == TRUE) {
- panic_written = panicwrite ();
- if (panic_written == ERRORS) {
- build_string (text_buffer, "Error writing panic file %s", panic_file);
- sleep (2);
- }
- else
- build_string (text_buffer, "Panic file %s written", panic_file);
- ring_bell ();
- panic_msg (text_buffer);
- }
- if (signum != 0)
- build_string (text_buffer, message, signum);
- else if (err == NIL_PTR)
- build_string (text_buffer, "%s", message);
- else
- build_string (text_buffer, "%s (Error: %s)", message, err);
- panic_msg (text_buffer);
-
- /* "normal" panic handling: */
- if (loading == FALSE) {
- QUED (); /* Try to save the file and quit */
- /* QUED returned: something wrong */
- sleep (2);
- panic_msg ("Aborted writing file in panic mode - trying to continue");
- panic_level --;
- return;
- }
- }
-
- if (panic_level < 3) {
- if (isscreenmode == TRUE) {
- set_cursor (0, YMAX);
- putchar ('\n');
- raw_mode (OFF);
- }
- delete_yank_file ();
- }
- exit (1) /* abort () sends IOT which would again be caught */;
- }
-
- void
- panic (message, err)
- register char * message;
- register char * err;
- {
- panicking (message, err, 0);
- }
-
- void
- panicio (message, err)
- register char * message;
- register char * err;
- {
- /* Should panic_level already be increased here ? */
- panic (message, err);
- }
-
- void
- catch_interrupt (signum)
- int signum;
- {
- panicking ("External signal %d caught - terminating", NIL_PTR, signum);
- catch_signals (catch_interrupt);
- }
-
- /*-------------------------------------------------------------------------*/
-
- /*
- * Memory allocation
- */
- #ifdef msdos
- #include <alloc.h>
- #define allocate farmalloc
- #define freemem farfree
- #else
- extern void * malloc ();
- extern void free ();
- #define allocate malloc
- #define freemem free
- #endif
-
- char *
- alloc (bytes)
- int bytes;
- {
- return allocate ((unsigned) bytes);
- /*
- char * p;
-
- if ((p = allocate ((unsigned) bytes)) == NIL_PTR)
- panic ("Out of memory", NIL_PTR);
- return p;
- */
- }
-
- void
- free_space (p)
- char * p;
- {
- freemem (p);
- }
-
- /*
- * free header list
- */
-
- #define pointersize sizeof (void *)
- #define blocksizeof(typ) ((sizeof (typ) + pointersize - 1) / pointersize * pointersize)
-
- LINE * free_header_list = NIL_LINE;
-
- void
- alloc_headerblock (n)
- int n;
- {
- LINE * new_header;
- LINE * new_list;
- int i = 0;
-
- new_list = (LINE *) alloc (n * blocksizeof (LINE));
- if (new_list == NIL_LINE) free_header_list = NIL_LINE;
- else while (i < n) {
- new_header = (LINE *) ((long) new_list + i * blocksizeof (LINE));
- new_header->next = free_header_list;
- free_header_list = new_header;
- i ++;
- }
- }
-
- LINE *
- alloc_header ()
- {
- /* return (LINE *) alloc (sizeof (LINE)); */
- LINE * new_header;
-
- if (free_header_list == NIL_LINE) {
- alloc_headerblock (64);
- if (free_header_list == NIL_LINE) alloc_headerblock (16);
- if (free_header_list == NIL_LINE) alloc_headerblock (4);
- if (free_header_list == NIL_LINE) alloc_headerblock (1);
- if (free_header_list == NIL_LINE) return NIL_LINE;
- }
- new_header = free_header_list;
- free_header_list = free_header_list->next;
- return new_header;
- }
-
- void
- free_header (hp)
- LINE * hp;
- {
- /* freemem (hp); */
- hp->next = free_header_list;
- free_header_list = hp;
- }
-
- /*
- * Basename () finds the absolute name of the file out of a given path_name.
- */
- #ifdef UNUSED
- char *
- basename (path)
- char * path;
- {
- register char * ptr = path;
- register char * last = NIL_PTR;
-
- while (* ptr != '\0') {
- if (* ptr == '/')
- last = ptr;
- ptr ++;
- }
- if (last == NIL_PTR)
- return path;
- if (* (last + 1) == '\0') { /* E.g. /usr/tmp/pipo/ */
- * last = '\0';
- return basename (path); /* Try again */
- }
- return last + 1;
- }
- #endif
-
- /*
- * Unnull () changes a NULL string pointer into an empty string pointer
- * to allow easy feading of string results into build_string / sprintf
- */
- char *
- unnull (s)
- char * s;
- {
- if (s == NIL_PTR) return "";
- else return s;
- }
-
- /*
- * Output an (unsigned) long in a 10 digit field without leading zeros.
- * It returns a pointer to the first digit in the buffer.
- */
- char *
- num_out (number)
- long number;
- {
- static char num_buf [11]; /* Buffer to build number */
- register long digit; /* Next digit of number */
- register long pow = 1000000000L; /* Highest ten power of long */
- FLAG digit_seen = FALSE;
- int i;
-
- for (i = 0; i < 10; i ++) {
- digit = number / pow; /* Get next digit */
- if (digit == 0L && digit_seen == FALSE && i != 9)
- num_buf [i] = ' ';
- else {
- num_buf [i] = '0' + (char) digit;
- number -= digit * pow; /* Erase digit */
- digit_seen = TRUE;
- }
- pow /= 10L; /* Get next digit */
- }
- num_buf [11] = '\0';
- for (i = 0; num_buf [i] == ' '; i ++) /* Skip leading spaces */
- ;
- return & num_buf [i];
- }
-
- /*
- * Build_string () prints the arguments as described in fmt, into the buffer.
- * %s indicates a string argument, %d indicates an integer argument.
- */
- #ifndef build_string /* otherwise build_string is sprintf */
- /* VARARGS */
- void
- build_string (buf, fmt, args)
- register char * buf, * fmt;
- int args;
- {
- int * argptr = & args;
- char * scanp;
- FLAG islong;
-
- while (* fmt) {
- if (* fmt == '%') {
- fmt ++;
- if (* fmt == 'l') {islong = TRUE; fmt ++;}
- else islong = FALSE;
- switch (* fmt ++) {
- case 's' :
- scanp = (char *) * argptr;
- break;
- case 'd' :
- if (islong == TRUE) {
- scanp = num_out ((long) * ((long *) argptr));
- if (sizeof (long) > sizeof (int)) argptr ++;
- break;
- }
- else {
- scanp = num_out ((long) * argptr);
- break;
- }
- case 'D' :
- scanp = num_out ((long) * ((long *) argptr));
- if (sizeof (long) > sizeof (int)) argptr ++;
- break;
- default :
- scanp = "";
- }
- while (* buf ++ = * scanp ++)
- ;
- buf --;
- argptr ++;
- }
- else
- * buf ++ = * fmt ++;
- }
- * buf = '\0';
- }
- #endif /* ndef build_string */
-
- /*
- * make_number () converts a string into a natural number
- * returns the character after the last digit
- */
- int
- make_number (num, str)
- int * num;
- char * str;
- {
- register char * chpoi = str;
-
- * num = 0;
- while (* chpoi >= '0' && * chpoi <= '9' && quit == FALSE) {
- * num *= 10;
- * num += * chpoi - '0';
- chpoi ++;
- }
- return * chpoi;
- }
-
- /*
- * Length_of () returns the number of characters in the string `string'
- * excluding the '\0'.
- */
- int
- length_of (string)
- register char * string;
- {
- register int count = 0;
-
- if (string != NIL_PTR) {
- while (* string ++ != '\0')
- count ++;
- }
- return count;
- }
-
- /*
- * text_length_of () returns the number of characters in the string `string'
- * up to and excluding the first '\n'.
- */
- int
- text_length_of (string)
- register char * string;
- {
- register int count = 0;
-
- if (string != NIL_PTR) {
- while (* string != '\0' && * string != '\n') {
- string ++;
- count ++;
- }
- }
- return count;
- }
-
- /*
- * Copy_string () copies the string `from' into the string `to'. `To' must be
- * long enough to hold `from'.
- */
- void
- copy_string (to, from)
- register char * to;
- register char * from;
- {
- while ((* to ++ = * from ++) != '\0')
- ;
- }
-
- /*-------------------------------------------------------------------------*/
-
- /*
- * serrorof delivers the error message of the given errno value.
- * serror delivers the error message of the current errno value.
- * geterrno just returns the current errno value.
- */
- #ifdef vms
- /* #define includeerrno */
- # ifdef includeerrno
- # include <errno.h>
- # else
- extern volatile int noshare errno;
- extern volatile int noshare vaxc$errno; /* VMS error code when errno = EVMSERR */
- # define EVMSERR 65535
- extern volatile int noshare sys_nerr;
- extern volatile char noshare * sys_errlist [];
- # endif
- #else
- extern int errno;
- extern int sys_nerr;
- extern char * sys_errlist [];
- #endif
-
- char *
- serrorof (errnum)
- int errnum;
- {
- if ((errnum < 0) || (errnum >= sys_nerr))
- { static char s [20];
- #ifdef vms
- if (errnum == EVMSERR)
- build_string (s, "VMS error %d", vaxc$errno);
- else
- #endif
- build_string (s, "Unknown error %d", errnum);
- return s;
- }
- else return sys_errlist [errnum];
- }
-
- char *
- serror ()
- { return serrorof (errno); }
-
- int
- geterrno ()
- { return errno; }
-
- /* ================================================================== *
- * Output *
- * ================================================================== */
-
- #ifdef msdos
- #define iscontrol(c) (((c) == '\177') || ((uchar) c < (uchar) ' '))
- #else
- #define iscontrol(c) (((c) == '\177') || ((uchar) ((c) & '\177') < (uchar) ' '))
- #endif
- #define controlchar(c) (((c) == '\177') ? '?' : (c) + '@')
-
- /*
- * Bad_write () is called when a write failed. Notify the user.
- */
- void
- bad_write (fd)
- int fd;
- {
- if (fd == output_fd) { /* Cannot write to terminal? */
- raw_mode (OFF);
- panicio ("Write error on terminal", NIL_PTR);
- }
-
- clear_buffer (); /* out_count = 0; */
- ring_bell ();
- error ("Write aborted (File incomplete): ", serror ());
- }
-
- /*
- * Flush the I/O buffer on filedescriptor fd.
- flush () is (void) flush_buffer (output_fd)
- */
- int
- flush_buffer (fd)
- int fd;
- {
- if (out_count <= 0) /* There is nothing to flush */
- return FINE;
- #ifdef conio
- if (fd == output_fd) {
- cputs (screen);
- }
- #else
- #ifdef BorlandC
- if (fd == output_fd) {
- screen [out_count] = '\0';
- /* don't ask me why that crazy compiler doesn't work with write () below */
- printf ("%s", screen);
- }
- #endif
- #endif
- else
- if (write (fd, screen, out_count) != out_count) {
- bad_write (fd);
- return ERRORS;
- }
- clear_buffer (); /* Empty buffer: out_count = 0; */
- return FINE;
- }
-
- /*
- * Write_char does a buffered output.
- putchar (c) is (void) writechar (output_fd, (c))
- */
- int
- writechar (fd, c)
- int fd;
- char c;
- {
- if (c == '\n') if (fd == output_fd) {
- if (writechar (fd, '\015') == ERRORS) return ERRORS;
- }
- screen [out_count ++] = c;
- if (out_count == screen_BUFL) /* Flush on screen_BUFL chars */
- return flush_buffer (fd);
- #ifdef DEBUG
- if (fd == output_fd) flush ();
- #endif
- return FINE;
- }
-
- /*
- * Writestring writes the given string on the given filedescriptor.
- * (buffered via writechar via screen !)
- putstring (str) is (void) writestring (output_fd, (str))
- */
- int
- writestring (fd, text)
- register int fd;
- register char * text;
- {
- while (* text)
- if (writechar (fd, * text ++) == ERRORS)
- return ERRORS;
- return FINE;
- }
-
- /*
- * Print string on terminal, printing controls with ^.
- */
- int lpos = 0;
-
- void
- print_char (c)
- register uchar c;
- {
- lpos ++;
- if (iscontrol (c)) {
- putchar ('^');
- lpos ++;
- putchar (controlchar (c));
- }
- else putchar (c);
- }
-
- int
- printlim_char (c, limit)
- register uchar c;
- register int limit;
- {
- if (lpos == limit) {putchar (SHIFT_MARK); return ERRORS;}
- lpos ++;
- if (iscontrol (c)) {
- putchar ('^');
- if (lpos == limit) {putchar (SHIFT_MARK); return ERRORS;}
- lpos ++;
- putchar (controlchar (c));
- }
- else putchar (c);
- return FINE;
- }
-
- void
- printlim_string (text, limit)
- register char * text;
- register int limit;
- {
- lpos = 0;
- while (* text != '\0')
- if (printlim_char (* text ++, limit) == ERRORS)
- return;
- }
-
- void
- print_string (text)
- register char * text;
- {
- lpos = 0;
- while (* text != '\0')
- print_char (* text ++);
- }
-
- void
- put_blanks (endpos)
- int endpos;
- {
- int startpos = 0;
- while (startpos ++ <= endpos) putchar (' ');
- }
-
- void
- clear_wholeline ()
- {
- if (can_clear_eol == TRUE) clear_eol ();
- else put_blanks (XMAX);
- }
-
- void
- clear_lastline ()
- {
- if (can_clear_eol == TRUE) clear_eol ();
- else put_blanks (XMAX - 1);
- }
-
- /* ================================================================== *
- * Buffer oriented output *
- * ================================================================== */
-
- /*
- * Put_line prints the given line on the standard output.
- * If offset is not zero, printing will start at that x-coordinate.
- * If the FLAG clear_line is TRUE, then the screen line will be cleared
- * when the end of the line has been reached.
- line_print (line) is put_line (line, 0, TRUE, FALSE)
- * put_line is directly called only by S () and delete_text ()
- */
- void
- put_line (line, offset, clear_line, positioning)
- LINE * line; /* Line to print */
- int offset; /* Offset to start if positioning == FALSE */
- /* position if positioning == TRUE */
- FLAG clear_line; /* Clear to eoln if TRUE */
- FLAG positioning; /* positioning inside line if TRUE (for prop. fonts) */
- {
- register char * textp = line->text;
- register int count = get_shift (line->shift_count) * - SHIFT_SIZE;
- int count_ini = count;
- int tab_count; /* Used in tab expansion */
- int offset_start;
- int offset_stop;
-
- if (positioning == TRUE) {
- offset_start = 0;
- offset_stop = offset;
- } else {
- offset_start = offset;
- offset_stop = XBREAK;
- }
-
- /* Skip all chars as indicated by the offset_start and the shift_count field */
- while (count < offset_start) {
- if (is_tab (* textp ++))
- count = tab (count);
- else
- count ++;
- }
-
- if (count == 0 && count_ini < 0 && SHIFT_BEG != '\0') {
- putchar (SHIFT_BEG);
- count ++;
- if (! is_tab (* textp)) textp ++;
- }
-
- while (* textp != '\n' && count < offset_stop) {
- if (is_tab (* textp)) { /* Expand tabs to spaces */
- tab_count = tab (count);
- while (count < offset_stop && count < tab_count) {
- count ++;
- putchar (TABchar);
- }
- textp ++;
- }
- else {
- if (iscontrol (* textp)) {
- reverse_on ();
- putchar (controlchar (* textp));
- reverse_off ();
- textp ++;
- }
- else
- putchar (* textp ++);
- count ++;
- }
- }
-
- if (positioning == TRUE) {
- /* self-made cursor for terminals (such as xterm)
- which have display problems with proportional screen fonts
- and their cursor */
- reverse_on ();
- if (* textp != '\n') putchar (* textp);
- else if (RET_MARK != '\0') putchar (RET_MARK);
- else putchar (' ');
- reverse_off ();
- set_cursor (0, YMAX);
- }
- else /* (positioning == FALSE) */ {
- /* If line is longer than XBREAK chars, print the shift_mark */
- if (count == XBREAK && * textp != '\n') {
- putchar (SHIFT_MARK);
- count ++;
- }
-
- /* Mark end of line if so desired */
- if (* textp == '\n' && RET_MARK != '\0') {
- putchar (RET_MARK);
- count ++;
- if (RET_BLANK) {
- while (count < XBREAK) {
- putchar (RET_BLANK);
- count ++;
- }
- if (RET_BLANK2 && count <= XBREAK) {
- putchar (RET_BLANK2);
- count ++;
- }
- }
- }
-
- /* Clear the rest of the line if clear_line is TRUE */
- if (clear_line == TRUE) {
- if (can_clear_eol == TRUE) {
- if (count <= XBREAK) clear_eol ();
- }
- else {
- while (count ++ <= XBREAK) /* clear up to XMAX */
- putchar (' ');
- }
- }
- }
- }
-
- /*
- * set_cursor_xy sets the cursor by either directly calling set_cursor
- * or, in the case of proportional font support, reprinting the line
- * up to the x position
- */
- void
- set_cursor_xy ()
- {
- if (proportional == TRUE) {
- set_cursor (0, y);
- if (x != 0) put_line (cur_line, x, FALSE, TRUE);
- /* cur_line may still be undefined if x == 0 */
- }
- else set_cursor (x, y);
- }
-
- /*
- * Proceed returns the count'th line after `line'. When count is negative
- * it returns the count'th line before `line'. When the next (previous)
- * line is the tail (header) indicating EOF (tof) it stops.
- */
- LINE *
- proceed (line, count)
- register LINE * line;
- register int count;
- {
- if (count < 0)
- while (count ++ < 0 && line != header)
- line = line->prev;
- else
- while (count -- > 0 && line != tail)
- line = line->next;
- return line;
- }
-
- /*
- * Reset assigns bot_line, top_line and cur_line according to `head_line'
- * which must be the first line of the screen, and a y-coordinate,
- * which will be the current y-coordinate (if it isn't larger than last_y)
- */
- void
- reset (head_line, screen_y)
- LINE * head_line;
- int screen_y;
- {
- register LINE * line;
-
- top_line = line = head_line;
-
- /* Search for bot_line (might be last line in file) */
- for (last_y = 0; last_y < total_lines - 1 && last_y < SCREENMAX
- && line->next != tail; last_y ++)
- line = line->next;
-
- bot_line = line;
- y = (screen_y > last_y) ? last_y : screen_y;
-
- /* Set cur_line according to the new y value */
- cur_line = proceed (top_line, y);
- }
-
- /*
- * Display line at screen line y_pos if it lies between y_min and y_max.
- * If it is no text line (end of file), clear screen line.
- */
- void
- display_line_at (y_pos, line, y_min, y_max, first)
- int y_pos, y_min, y_max;
- register LINE * line;
- FLAG first;
- {
- line = proceed (line, y_pos - y_min);
- if (y_pos >= y_min && y_pos <= y_max) {
- set_cursor (0, y_pos);
- if (line == tail) clear_wholeline ();
- else {
- if (first == FALSE) {
- if (display_delay >= 0) flush ();
- if (display_delay > 0)
- #ifdef msdos
- delay (display_delay);
- #else
- (void) usleep (1000 * display_delay);
- #endif
- }
- line_print (line);
- }
- }
- }
-
- /*
- * Display () shows count + 1 lines on the terminal starting at the given
- * coordinates. At end of file, the rest of the screen is blanked.
- * When count is negative, a backwards print from `line' will be done.
- */
- void
- display (y_coord, line, count, new_pos)
- int y_coord, new_pos;
- register LINE * line;
- register int count;
- {
- int y_max = y_coord + count;
- int y_off;
-
- /* Find new startline if count is negative */
- if (count < 0) {
- line = proceed (line, count);
- count = - count;
- }
-
- display_line_at (new_pos, line, y_coord, y_max, TRUE);
- y_off = 0;
- while (y_off < count) {
- y_off ++;
- display_line_at (new_pos - y_off, line, y_coord, y_max, FALSE);
- display_line_at (new_pos + y_off, line, y_coord, y_max, FALSE);
- }
- #ifdef UNUSED
- /* old code, building the display from top to bottom (how boring): */
- /* with this code, XBREAK must be set to XMAX - 1 */
- /* Print the lines */
- set_cursor (0, y_coord);
- while (line != tail && count -- >= 0) {
- line_print (line);
- line = line->next;
- }
-
- /* Print the blank lines (if any) */
- if (loading == FALSE) {
- while (count -- >= 0) {
- clear_eol ();
- putchar ('\n');
- }
- }
- #endif
- }
-
- /* ================================================================== *
- * Mined Terminal Dialog *
- * ================================================================== */
-
- /*
- * promptyn reads in a 'y' or 'n' character.
- */
- uchar
- promptyn ()
- {
- register uchar c;
- while ((c = readchar ()) != 'y' && c != 'n' && c != '\033' && quit == FALSE) {
- ring_bell ();
- flush ();
- }
- if (c == '\033') quit = TRUE;
- return c;
- }
-
- /*
- * In case of a QUIT signal, swallow the dummy char generated by catchquit ()
- * called by re_search () and change ()
- */
- void
- swallow_dummy_quit_char ()
- {
- #ifdef UNUSED
- (void) readchar (); /* Swallow away a quit character delivered by QUIT */
- /* Not needed because this character is ignored by being the CANCEL command */
- #endif
- }
-
- /*
- * Readchar () reads one character from the terminal.
- * There are problems due to interruption of the read operation by signals
- * (QUIT, WINCH). The waitingforinput flag is only a partial solution.
- * Unix doesn't provide sufficient facilities to handle these situations
- * neatly and properly. Moreover, different Unix versions yield different
- * surprising effects. However, the use of select () could still be
- * an improvement.
- */
- int
- readchar ()
- {
- register uchar c;
-
- #ifdef msdos
- FLAG waiting;
-
- if (winchg == TRUE && waitingforinput == FALSE) RDwin ();
- /* In the Unix version, this is now done in __readchar () */
- waiting = waitingforinput;
- /* must be saved since in the MSDOS version, readchar can
- be called recursively */
- #endif
- waitingforinput = TRUE;
-
- c = _readchar ();
-
- #ifdef msdos
- waitingforinput = waiting;
- #else
- waitingforinput = FALSE;
- #endif
-
- /* the modification if (quit == TRUE) c = QUITCHAR; (now in __readchar)
- must not be placed after resetting the flag waitingforinput = FALSE; .
- Otherwise a QUIT signal coming in just between these two would
- discard the last valid character just taken up. */
-
- return c;
- }
-
- /*-------------------------------------------------------------------------*/
-
- #ifndef msdos
-
- extern struct {
- char * fk;
- void (* fp) ();
- } keycode [];
-
- #define MAXCODELEN 7 /* max. length of function key sequence to be detected,
- depending on the keycode table */
-
- /*
- * queue collects the keys of an Escape sequence typed in until the
- * sequence can be detected or rejected.
- * If the queue is not empty, queue [0] contains the character next
- * to be delivered by _readchar () (it's not a ring buffer).
- * The queue contents is always terminated by a '\0', so queue can also
- * be taken as a character string.
- */
- static uchar queue [MAXCODELEN + 1], * endp = queue;
-
- int
- q_empty ()
- {
- return (endp == queue ? 1 : 0);
- }
-
- int
- q_notfull ()
- {
- return (endp - queue == MAXCODELEN ? 0 : 1);
- }
-
- void
- q_clear ()
- {
- endp = queue;
- }
-
- int
- q_len ()
- {
- return endp - queue;
- }
-
- void
- q_put (c)
- uchar c;
- /* queue must not be full prior to this call! */
- {
- * endp = c;
- * ++ endp = '\0';
- }
-
- uchar
- q_get ()
- {
- uchar c;
- register uchar * pd, * ps;
-
- c = * queue; pd = queue; ps = pd + 1;
- while (ps <= endp) * pd ++ = * ps ++;
- if (endp > queue) endp --;
- return c;
- }
-
- /*
- * Look up key sequence in keycode table.
- * findkey (str) >= 0: str == keycode [findkey (str)].fk
- * == -1: str is prefix of some entry in keycode
- * == -2: str is not contained in keycode
- */
- int
- findkey (str)
- char * str;
- {
- static int lastmatch = 0; /* last index with string matching prefix */
- register int i;
-
- if (keycode [0].fk == NIL_PTR) return -2;
- i = lastmatch;
- do {
- if (strncmp (str, keycode [i].fk, strlen (str)) == 0) {
- lastmatch = i;
- return (strlen (str) == strlen (keycode [i].fk) ? i : -1);
- }
- ++ i;
- if (keycode [i].fk == NIL_PTR) i = 0;
- } while (i != lastmatch);
- return -2;
- }
-
- /*
- * Is a character available within a specified number of milliseconds ?
- */
- int
- char_ready_within (msec)
- int msec;
- {
- return (q_len () > 0) || inputreadyafter (input_fd, msec);
- }
-
- #else /* def msdos: */
-
- int
- char_ready_within (msec)
- int msec;
- {
- return inputreadyafter (input_fd, msec);
- }
-
- #endif /* def msdos */
-
- void (* keyproc) () = I;
- uchar (* accentproc) ();
-
- /*
- * Read a character from terminal, considering function keys and
- * composing special character of an 8 bit character set.
- * _readchar () takes the following actions:
- * - function key sequences according to the table 'keycode' are
- * transformed into a special controlling character which is
- * assigned the function FUNKEY. Also the intended editor function,
- * as taken from the table 'keycode', is saved in a variable for
- * use by FUNKEY.
- * - the prefix keys for diacritic and special characters are
- * combined with the following key to make up the character.
- */
- int
- _readchar ()
- {
- register uchar ch;
- #ifndef msdos
- int res;
- #endif
-
- #ifndef msdos
- if (q_len () > 0) return q_get ();
- #endif
-
- ch = __readchar ();
-
- if (ch == '\000') {
- ch = __readchar ();
- keyproc = pc_key_map [ch];
- #ifdef DEBUG
- if ((voidfunc) keyproc == (voidfunc) I) return ch;
- /* (voidfunc) is an identity cast here. It seems to be required
- for the sake of the apparently totally rotten microvax compiler */
- #endif
- accentproc = (charfunc) keyproc;
- if ((accentproc == grave) || (accentproc == circumflex)
- || (accentproc == acute) || (accentproc == diaeresis)
- || (accentproc == tilde) || (accentproc == angstrom))
- {ch = (* accentproc) (readchar ());
- keyproc = I;
- return ch;
- }
- else return FUNcmd /* index of FUNKEY */;
- }
- #ifndef msdos
- else if (ch == '\033') {
- /* q_clear (); */
- q_put (ch);
- while ((res = findkey (queue)) == -1 /* prefix of table entry */
- && q_notfull ()
- && inputreadyafter (input_fd, 300)
- )
- q_put (__readchar ());
- if (quit == TRUE) return '\0';
- else if (res < 0) /* key pattern not detected in keycode table */
- /* {if (q_len () > 1) return 0;
- else return ch;} */
- return q_get () /* just deliver the typed characters */;
- else {
- q_clear ();
- keyproc = keycode [res].fp;
- accentproc = (charfunc) keyproc;
- if ((accentproc == grave) || (accentproc == circumflex)
- || (accentproc == acute) || (accentproc == diaeresis)
- || (accentproc == tilde) || (accentproc == angstrom))
- {ch = (* accentproc) (readchar ());
- keyproc = I;
- return ch;
- }
- else return FUNcmd /* index of FUNKEY */;
- }
- }
- #endif
- else
- return ch;
- }
-
- /* ================================================================== *
- * Status Line Dialog *
- * ================================================================== */
-
- /*
- * Display a line telling how many chars and lines the file contains. Also tell
- * whether the file is readonly and/or modified.
- fstatus (mess, cnt) is file_status ((mess), (cnt), file_name, \
- total_lines, TRUE, writable, modified, viewonly)
- */
- /* directly called only from WB: file_status
- (msg_done, chars_saved, file_name, lines_saved, FALSE, TRUE, FALSE, FALSE); */
- void
- file_status (message, count, file, lines, textstat, writefl, changed, viewing)
- char * message;
- register long count; /* Contains number of characters in file */
- char * file;
- int lines;
- FLAG textstat, writefl, changed, viewing;
- {
- register LINE * line;
- register int line_num = 0;
- int line_number = 1;
- static char msg [maxLINE_LEN + 40]; /* Buffer to hold line */
- char yank_msg [maxLINE_LEN]; /* Buffer for msg of yank_file */
-
- if (count < 0) /* Not valid. Count chars in file */
- for (line = header->next; line != tail; line = line->next) {
- count += length_of (line->text);
- line_num ++;
- if (line == cur_line) line_number = line_num;
- }
-
- if (yank_status == VALID && textstat == TRUE) /* Append buffer info */
- /* build_string (yank_msg, " Buffer: %ld char%s.", chars_saved,
- (chars_saved == 1L) ? "" : "s");
- */
- build_string (yank_msg, "");
- /* Empty paste buffer is only an initial condition and thus this
- would be no significant information; since buffer contents
- may be appended, the exact count is not available anyway. */
- else
- yank_msg [0] = '\0';
-
- build_string (msg,
- (textstat == TRUE)
- ? "%s %s%s%s%s, %d line%s, %ld char%s. Line %d.%s"
- : "%s %s%s%s%s, %d line%s, %ld char%s.",
- message,
- (rpipe == TRUE && * message != '[') ?
- "standard input" : file,
- /* previously only basename (file) was printed */
- (viewing == TRUE) ? " (View only)" : "",
- (changed == TRUE) ? " (modified)" : "",
- (writefl == FALSE) ? " (Readonly)" : "",
- lines, (lines == 1) ? "" : "s",
- count, (count == 1L) ? "" : "s",
- line_number,
- yank_msg);
-
- status_msg (msg); /* Print the information */
- }
-
- /*
- * Input () reads a string from the terminal.
- * Return values:
- * when QUIT character typed => ERRORS
- * when empty input and clearfl == TRUE: NO_INPUT
- * else: FINE
- */
- int
- input (inbuf, clearfl)
- uchar * inbuf;
- FLAG clearfl;
- {
- register uchar * ptr;
- register uchar c;
-
- ptr = inbuf;
- * ptr = '\0';
- while (quit == FALSE) {
- flush ();
- if (lpos >= XBREAK) pagewrapped = TRUE;
- switch (c = readchar ()) {
- case '\b' : /* Erase previous char */
- case '\177' /* DEL */ :
- if (ptr > inbuf) {
- ptr --;
- reverse_off ();
- if (Chinese == TRUE && inmultichar (inbuf, ptr)) {
- ptr --;
- putstring (" \b\b\b \b\b");
- lpos = lpos - 2;
- } else if (iscontrol (* ptr)) {
- putstring (" \b\b\b \b\b");
- lpos = lpos - 2;
- } else {
- putstring (" \b\b \b");
- lpos = lpos - 1;
- }
- reverse_on ();
- putstring (" \b");
- * ptr = '\0';
- } else
- ring_bell ();
- break;
- case QUITCHAR :
- case '\033' :
- quit = TRUE;
- break;
- case '\n' : /* End of input */
- case '\015' :
- /* If inbuf is empty clear status_line */
- return (ptr == inbuf && clearfl == TRUE) ?
- NO_INPUT : FINE;
- default :
- if (c == control_prefix /* ^V/^P */) {
- c = readchar ();
- if (c == ring || c == ',')
- {c = angstrom (readchar ());}
- else switch (c) {
- case '"': {c = diaeresis (readchar ()); break;}
- case '\'': {c = acute (readchar ()); break;}
- case '`': {c = grave (readchar ()); break;}
- case '^': {c = circumflex (readchar ()); break;}
- case '~': {c = tilde (readchar ()); break;}
- default:
- if (c == '?') c = '\177';
- if (c != '\177') c = c & '\237';
- }
- }
- if (Chinese == TRUE && multichar (c)) {
- if ((ptr - inbuf) + 1 < maxLINE_LEN) {
- * ptr ++ = c;
- print_char (c);
- c = readchar ();
- * ptr ++ = c;
- print_char (c);
- * ptr = '\0';
- putstring (" \b");
- }
- else
- ring_bell ();
- } else if ((ptr - inbuf) < maxLINE_LEN) {
- if ((c > '\0')) {
- * ptr ++ = c;
- * ptr = '\0';
- print_char (c);
- putstring (" \b");
- }
- else
- ring_bell ();
- }
- else
- ring_bell ();
- }
- }
- quit = FALSE;
- return ERRORS;
- }
-
- /*
- * Show concatenation of s1 and s2 on the status line (bottom of screen)
- * If revfl is TRUE, turn on reverse video on both strings. Set stat_visible
- * only if bottom_line is visible.
- * The return value is FINE except for get_string, where it is taken
- * from the call to input ().
- status_line (str1, str2) is (void) bottom_line (ON, (str1), (str2), NIL_PTR, FALSE)
- status_msg (str) is status_line (str, NIL_PTR)
- status_beg (str) is (void) bottom_line (ON, (str), NIL_PTR, NIL_PTR, TRUE)
- error (str1, str2) is (void) bottom_line (ON, (str1), (str2), NIL_PTR, FALSE)
- clear_status () is (void) bottom_line (OFF, NIL_PTR, NIL_PTR, NIL_PTR, FALSE)
- get_string (str1, str2, fl) is bottom_line (ON, (str1), NIL_PTR, (str2), fl)
- */
- FLAG lastrevfl;
- char * lastinbuf;
- FLAG input_active = FALSE;
- char status_buf [maxLINE_LEN];
-
- void
- rd_bottom_line ()
- {
- set_cursor (0, YMAX);
- reverse_on ();
- if (lastinbuf == NIL_PTR)
- printlim_string (status_buf, XBREAK);
- else {
- print_string (status_buf);
- print_string (lastinbuf);
- }
- if (! input_active) {
- reverse_off ();
- set_cursor_xy (); /* Set cursor back to old position */
- }
- flush (); /* Perform the actual screen output */
- }
-
- int
- bottom_line (revfl, s1, s2, inbuf, statfl)
- FLAG revfl;
- char * s1, * s2;
- char * inbuf;
- FLAG statfl;
- {
- int ret = FINE;
-
- if (inbuf != NIL_PTR) * inbuf = '\0';
- lastrevfl = revfl;
- lastinbuf = inbuf;
-
- if (pagewrapped == TRUE) {
- status_buf [0] = '\0';
- RD ();
- pagewrapped = FALSE;
- }
-
- build_string (status_buf, " %s%s ", unnull (s1), unnull (s2));
- /* (s1 == NIL_PTR) ? "" : s1, (s2 == NIL_PTR) ? "" : s2); */
-
- if (revfl == ON && stat_visible == TRUE) {
- set_cursor (0, YMAX);
- clear_lastline ();
- }
- set_cursor (0, YMAX);
- if (revfl == ON) { /* Print rev. start sequence */
- reverse_on ();
- stat_visible = TRUE;
- }
- else { /* Used as clear_status () */
- reverse_off ();
- stat_visible = FALSE;
- }
-
- if (inbuf == NIL_PTR)
- printlim_string (status_buf, XBREAK);
- else {
- print_string (status_buf);
- input_active = TRUE;
- ret = input (inbuf, statfl);
- input_active = FALSE;
- }
-
- /* Print normal video */
- reverse_off ();
- if (can_clear_eol == TRUE) clear_eol ();
- else {
- put_blanks (XMAX - 1 - lpos);
- set_cursor (lpos, YMAX);
- }
-
- if (inbuf != NIL_PTR) {
- set_cursor (0, YMAX);
- }
- else if (statfl == TRUE)
- reverse_on ();
- else
- set_cursor_xy (); /* Set cursor back to old position */
-
- flush (); /* Perform the actual screen output */
- if (ret != FINE) clear_status ();
- return ret;
- }
-
- /*
- * Get_number () reads a number from the terminal.
- * The last character typed in is returned.
- * ERRORS is returned on a bad number or on interrupted input.
- * The resulting number is put into the integer the arguments points to.
- */
- int
- get_number (message, firstdigit, result)
- char * message;
- char firstdigit;
- int * result;
- {
- register int index;
- register int count;
-
- status_beg (message);
-
- if (firstdigit > '\0')
- index = firstdigit;
- else
- index = readchar ();
-
- if (index == QUITCHAR) quit = TRUE;
- if (index == '\033') quit = TRUE;
- if (quit == FALSE && (index < '0' || index > '9')) {
- error ("Bad number", NIL_PTR);
- return ERRORS;
- }
-
- /* Convert input to a decimal number */
- count = 0;
- while (index >= '0' && index <= '9' && quit == FALSE) {
- print_char (index); flush ();
- if (lpos >= XBREAK) pagewrapped = TRUE;
- count *= 10;
- count += index - '0';
- index = readchar ();
- if (index == QUITCHAR) quit = TRUE;
- if (index == '\033') quit = TRUE;
- }
-
- clear_status ();
- if (quit == TRUE) {
- clear_status ();
- return ERRORS;
- }
- * result = count;
- return index;
- }
-
- /*
- * get_digits () reads in a number. In contrast to get_number, it does no
- * echoing, no messaging, and it does not require any digits at all.
- * The last character typed in is returned.
- * The resulting number is put into the integer the arguments points to.
- */
- int
- get_digits (result)
- int * result;
- {
- register int index;
- register int count;
-
- index = readchar ();
- if (index == QUITCHAR) quit = TRUE;
- * result = -1;
- /* Convert input to a decimal number */
- count = 0;
- while (index >= '0' && index <= '9' && quit == FALSE) {
- count *= 10;
- count += index - '0';
- * result = count;
- index = readchar ();
- if (index == QUITCHAR) quit = TRUE;
- }
-
- if (quit == TRUE) {
- return QUITCHAR;
- }
- return index;
- }
-
- /*
- * Get_file () reads a filename from the terminal.
- */
- int
- get_file (message, file)
- char * message, * file;
- {
- int ret = get_string (message, file, TRUE);
- #ifndef msdos
- char * filei;
- char file1 [maxLINE_LEN];
-
- if (file [0] == '~' && file [1] == '/') {
- filei = file; filei ++;
- build_string (file1, "%s%s", unnull (getenv ("HOME")), filei);
- build_string (file, file1);
- }
- #endif
- return ret;
- }
-
- /* ================================================================== *
- * text modification routines *
- * ================================================================== */
-
- extern void viewonlyerr ();
-
- /*
- * make_line installs the buffer into a LINE structure.
- * It returns a pointer to the allocated structure.
- */
- LINE *
- make_line (buffer, length)
- char * buffer;
- int length;
- {
- register LINE * new_line = alloc_header ();
-
- if (new_line == NIL_LINE) {
- ring_bell ();
- error ("Cannot allocate more memory for new line header", NIL_PTR);
- return NIL_LINE;
- } else {
- new_line->text = alloc (length + 1);
- if (new_line->text == NIL_PTR) {
- ring_bell ();
- error ("Cannot allocate more memory for new line", NIL_PTR);
- return NIL_LINE;
- } else {
- new_line->shift_count = 0;
- copy_string (new_line->text, buffer);
- return new_line;
- }
- }
- }
-
- /*
- * Line_insert () inserts a new line with text pointed to by `string'.
- * It returns the address of the new line.
- */
- LINE *
- line_insert (line, string, len)
- register LINE * line;
- char * string;
- int len;
- {
- register LINE * new_line;
-
- /* Allocate space for LINE structure and text */
- new_line = make_line (string, len);
-
- if (new_line != NIL_LINE) {
- /* Install the line into the double linked list */
- new_line->prev = line;
- new_line->next = line->next;
- line->next = new_line;
- new_line->next->prev = new_line;
- /* Increment total_lines */
- total_lines ++;
- }
- return new_line;
- }
-
- /*
- * Insert () insert the string `string' at the given line and location.
- */
- int
- insert (line, location, string)
- register LINE * line;
- char * location, * string;
- {
- register char * bufp = text_buffer; /* Buffer for building line */
- register char * textp = line->text;
- char * newtext;
-
- if (viewonly == TRUE)
- {viewonlyerr (); return ERRORS;}
-
- if (length_of (textp) + text_length_of (string) >= MAX_CHARS) {
- error ("Line too long", NIL_PTR);
- return ERRORS;
- }
-
- /* Copy part of line until `location' has been reached */
- while (textp != location)
- * bufp ++ = * textp ++;
-
- /* Insert string at this location */
- while (* string != '\0')
- * bufp ++ = * string ++;
- * bufp = '\0';
-
- /* First, allocate memory for next line contents to make sure the */
- /* operation succeeds or fails as a whole */
- newtext = alloc (length_of (text_buffer) + length_of (location) + 1);
- if (newtext == NIL_PTR) {
- ring_bell ();
- error ("Cannot allocate memory for insertion", NIL_PTR);
- return ERRORS;
- }
- else { /* Install the new text in this line */
- if (* (string - 1) == '\n') { /* Insert a new line */
- if (line_insert (line, location, length_of (location)) == NIL_LINE)
- return ERRORS;
- modified = TRUE;
- }
- else /* Append last part of line to text_buffer */
- copy_string (bufp, location);
-
- free_space (line->text);
- modified = TRUE;
- line->text = newtext;
- copy_string (line->text, text_buffer);
- return FINE;
- }
- }
-
- /*
- * Line_delete () deletes the argument line out of the line list. The pointer
- * to the next line is returned.
- */
- LINE *
- line_delete (line)
- register LINE * line;
- {
- register LINE * next_line = line->next;
-
- /* Delete the line */
- line->prev->next = line->next;
- line->next->prev = line->prev;
-
- /* Free allocated space */
- free_space (line->text);
- free_header (line);
-
- /* Decrement total_lines */
- total_lines --;
-
- return next_line;
- }
-
- /*
- * Delete_text () deletes all the characters (including newlines) between the
- * startposition and endposition and fixes the screen accordingly. It
- * displays the number of lines deleted.
- */
- FLAG
- delete_text (start_line, start_textp, end_line, end_textp)
- register LINE * start_line;
- LINE * end_line;
- char * start_textp, * end_textp;
- {
- register char * textp = start_line->text;
- register char * bufp = text_buffer; /* Storage for new line->text */
- LINE * line;
- LINE * after_end = end_line->next;
- int line_cnt = 0; /* Nr of lines deleted */
- int count = 0;
- int shift = 0; /* Used in shift calculation */
- int nx = x;
- FLAG ret = FINE;
- char * newtext;
-
- if (viewonly == TRUE)
- {viewonlyerr (); return ret;}
-
- modified = TRUE; /* File has been modified */
-
- /* Set up new line. Copy first part of start line until start_position. */
- while (textp < start_textp) {
- * bufp ++ = * textp ++;
- count ++;
- }
-
- /* Check if line doesn't exceed MAX_CHARS */
- if (count + length_of (end_textp) >= MAX_CHARS) {
- error ("Line too long", NIL_PTR);
- return ret;
- }
-
- /* Copy last part of end_line if end_line is not tail */
- copy_string (bufp, (end_textp != NIL_PTR) ? end_textp : "\n");
-
- /* Delete all lines between start and end_position (including end_line) */
- line = start_line->next;
- while (line != after_end && line != tail) {
- /* Here, the original mined compared with end_line->next which has
- already been discarded when the comparison should become true.
- This severe error remained undetected until I ported to MSDOS */
- line = line_delete (line);
- line_cnt ++;
- }
-
- /* Check if last line of file should be deleted */
- if (end_textp == NIL_PTR && length_of (start_line->text) == 1 && total_lines > 1) {
- start_line = start_line->prev;
- (void) line_delete (start_line->next);
- line_cnt ++;
- }
- else { /* Install new text */
- newtext = alloc (length_of (text_buffer) + 1);
- if (newtext == NIL_PTR) {
- ring_bell ();
- error ("No more memory after deletion", NIL_PTR);
- ret = ERRORS;
- } else {
- free_space (start_line->text);
- start_line->text = newtext;
- copy_string (start_line->text, text_buffer);
- }
- }
-
- /* Fix screen. First check if line is shifted. Perhaps we should shift it back */
- #ifdef UNUSED
- /* !!! This resulted in a positioning error when a line containing TABs */
- /* !!! was shifted back. So better leave it. */
- if (get_shift (start_line->shift_count)) {
- shift = (XBREAK - count_chars (start_line)) / SHIFT_SIZE;
- if (shift > 0) { /* Shift line `shift' back */
- if (shift >= get_shift (start_line->shift_count))
- start_line->shift_count = 0;
- else
- start_line->shift_count -= shift;
- nx += shift * SHIFT_SIZE; /* Reset x value */
- }
- }
- #endif
-
- if (line_cnt == 0) { /* Check if only one line changed */
- if (shift > 0) { /* Reprint whole line */
- set_cursor (0, y);
- line_print (start_line);
- }
- else { /* Just display last part of line */
- set_cursor_xy ();
- put_line (start_line, x, TRUE, FALSE);
- }
- move_to (nx, y); /* Reset cur_text */
- return ret;
- }
-
- shift = last_y; /* Save value */
- reset (top_line, y);
- if ((line_cnt <= SCREENMAX - y) && can_delete_line == TRUE) {
- clear_status ();
- display (y, start_line, 0, y);
- line = proceed (start_line, SCREENMAX - y - line_cnt + 1);
- while (line_cnt -- > 0) {
- delete_line (y + 1);
- if (line != tail) {
- set_cursor (0, SCREENMAX);
- line_print (line);
- line = line->next;
- }
- }
- }
- else
- display (y, start_line, shift - y, y);
- /* move_to ((line_cnt == 1) ? nx : 0, y); */
- move_to (nx, y);
- return ret;
- }
-
- /* ================================================================== *
- * End *
- * ================================================================== */
-